function log() {
    baseLog("/////////////////////////////////////////////////////////////////");
    baseLog("Hello chapter-11.js!");
}

function promiseBase() {
    {
        let p = new Promise(() => {});
        setTimeout(baseLog, 0, p);          // Promise {<pending>}
    }
    {
        let p = new Promise((resolve, reject) => {
            setTimeout(resolve, 2000);      // call resolve after 2 seconds
        });
        setTimeout(baseLog, 1000, p);      // Promise {<pending>}
        setTimeout(baseLog, 3000, p);      // Promise {<fulfilled>: undefined}
    }
    {
        let p = new Promise((resolve, reject) => {
            setTimeout(reject, 2000, 'reason');      // call resolve after 2 seconds
        });
        setTimeout(baseLog, 1000, p);      // Promise {<pending>}
        setTimeout(baseLog, 3000, p);      // Uncaught (in promise) reason, Promise {<rejected>: 'reason'}
    }
    {
        try {
            throw new Error('foo');     // Error: foo
        } catch(e) {
            baseLog(e);
        }
        try {
            Promise.reject(new Error('bar'));
        } catch(e) {
            baseLog(e);         // Uncaught (in promise) Error: bar
        }
    }
    {
        function onResolved(id) {
            setTimeout(baseLog, 0, id, 'resolved');
        }
        function onRejected(id) {
            setTimeout(baseLog, 0, id, 'rejected');
        }
        let p1 = new Promise((resolve, reject) => setTimeout(resolve, 1000));
        let p2 = new Promise((resolve, reject) => setTimeout(reject, 1000));
        p1.then(() => onResolved('p1'),
                () => onRejected('p1'));
        p2.then(() => onResolved('p2'),
                () => onRejected('p2'));
        // after 1 second, p1 ['resolved'], p2 ['rejected']
    }
    {
        let syncResolve;
        let p = new Promise((resolve) => {
            syncResolve = function() {
                console.log('1: invoking resolve()');
                resolve();
                console.log('2: resolve() returns');
            };
        });
        p.then(() => console.log('4: then() handler executes'));
        syncResolve();
        console.log('3: syncResolve()');
        // Actual outputs:
        // 1: invoking resolve()
        // 2: resolve() returns
        // 3: syncResolve() returns
        // 4: then() handler executes
    }
    {
        let p1 = Promise.resolve();
        p1.then(() => console.log('p1.then() onResolved'));
        console.log('p1.then() returens');
        let p2 = Promise.reject();
        p2.then(null, () => console.log('p2.then() onRejected'));
        console.log('p2.then() returns');
        let p3 = Promise.reject();
        p3.catch(() => console.log('p3.catch() onRejected'));
        console.log('p3.catch() returns');
        let p4 = Promise.resolve();
        p4.finally(() => console.log('p4.finally() onFinally'));
        console.log('p4.finally() returns');
       /**
        * output:
        * p1.then() returns
        * p2.then() returns
        * p3.catch() returns
        * p4.finally() returns
        * p1.then() onResolved
        * p2.then() onRejected
        * p3.catch() onRejected
        * p4.finally() onFinally
        */
    }
}

function asyncFuncion() {
    {
        async function foo() {
            console.log(1);
            return 3;
        }
        foo().then(console.log);
        console.log(2);
        /**
         * outputs:
         * 1 2 3
         */
    }
    {
        async function foo() {
            console.log(await Promise.resolve('foo'));
        }
        async function bar() {
            console.log(await 'bar');
        }
        async function baz() {
            console.log('baz');
        }
        foo();
        bar();
        baz();
        /**
         * output:
         * baz bar foo
         */
    }
    {
        async function foo() {
            console.log(2);
            await null;
            console.log(4);
        }
        console.log(1);
        foo();
        console.log(3);
        /**
         * output:
         * 1 2 3 4
         */
    }
    {
        async function foo() {
            console.log(2);
            console.log(await Promise.resolve(8));
            console.log(9);
        }
        async function bar() {
            console.log(4);
            console.log(await 6);
            console.log(7);
        }
        console.log(1);
        foo();
        console.log(3);
        bar();
        console.log(5);
        /**
         * output:
         * 1 2 3 4 5 6 7 8 9
         */
    }
}


///////////////////////////////////////////////////////////////////////////////////////
log();
promiseBase();
asyncFuncion();
